﻿using System;
using System.IO;
using System.Data.SqlClient;

namespace Browis.Package
{
    public class DataReadStream : Stream
    {
        public DataReadStream(SqlDataReader dr, int index)
        {
            dataReader = dr;
            columnIndex = index;
        }

        public DataReadStream(SqlDataReader dr, int index, string sType)
        {
            dataReader = dr;
            columnIndex = index;
            columnType = sType.ToLower();
        }

        /// <summary>
        /// 统一存储文件流的当前指针位置。
        /// </summary>
        private long position;

        /// <summary>
        /// 该流的SqlDataReader。
        /// </summary>
        private SqlDataReader dataReader;

        /// <summary>
        /// 该流的列索引。
        /// </summary>
        private int columnIndex;

        /// <summary>
        /// 该流的列类型
        /// </summary>
        private string columnType;


        /// <summary>
        /// 获取一个值，该值指示当前流是否支持读取。
        /// </summary>
        public override bool CanRead
        {
            get { return true; }
        }

        /// <summary>
        /// 获取一个值，该值指示当前流是否支持移动文件指针。
        /// </summary>
        public override bool CanSeek
        {
            get { return true; }
        }

        /// <summary>
        /// 获取一个值，该值指示当前流是否支持写入。
        /// </summary>
        public override bool CanWrite
        {
            get { return false; }
        }


        private byte[] content = null;        
        /// <summary>
        /// 获取用字节表示的流长度。
        /// </summary>
        public override long Length
        {
            get 
            {
                if (string.IsNullOrEmpty(columnType) || columnType.ToLower() == "byte[]")
                {
                    return dataReader.GetBytes(columnIndex, 0, null, 0, 0);
                }
                else
                {
                    if (content == null)
                    {
                        content = GetBytes(dataReader[columnIndex], columnType);
                    }
                    return content.Length;
                }
            }
        }

        /// <summary>
        /// 获取或设置当前流中的位置。
        /// </summary>
        public override long Position
        {
            get { return position; }
            set { Seek(value, SeekOrigin.Begin); }
        }

        public override void Flush()
        {
            throw new NotImplementedException();
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            switch (origin)
            {
                case SeekOrigin.Begin:
                    this.position = offset;
                    break;
                case SeekOrigin.Current:
                    this.position += offset;
                    break;
                case SeekOrigin.End:
                    this.position = this.Length + offset;
                    break;
            }
            if (this.position < 0)
                this.position = 0;

            if (this.position > this.Length)
                this.position = this.Length;

            return this.position;
        }

        public override void SetLength(long value)
        {
            throw new NotSupportedException("流不支持该操作");
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            if (buffer == null)
                throw new ArgumentNullException("buffer");

            if (offset < 0)
                throw new ArgumentOutOfRangeException("offset");

            if (count < 0)
                throw new ArgumentOutOfRangeException("count");

            if (buffer.Length < offset + count)
                throw new ArgumentException("缓存区长度过小");

            if (position + count > this.Length)
                count = (int)(this.Length - position);

            if (count == 0)
                return 0;
            //判断是否是流式读取，content为null表示是流式读取
            if (content == null)
            {
                count = (int)dataReader.GetBytes(columnIndex, this.position, buffer, offset, count);
            }
            else
            {
                count = count > content.Length - offset ? content.Length - offset : count;
                Array.Copy(content, this.position, buffer, offset, count);
            }
            this.position += count;

            return count;
        }

        private byte[] GetBytes(object value, string sTypeName)
        {
            byte[] buffer = null;
            switch (sTypeName)
            {
                case "bool":                    
                    buffer = BitConverter.GetBytes(Convert.ToBoolean(value));
                    break;
                case "int":
                    buffer = BitConverter.GetBytes(Convert.ToInt32(value));
                    break;
                case "uint":
                    buffer = BitConverter.GetBytes(Convert.ToUInt32(value));
                    break;
                case "long":
                    buffer = BitConverter.GetBytes(Convert.ToInt64(value));
                    break;
                case "ulong":
                    buffer = BitConverter.GetBytes(Convert.ToUInt64(value));
                    break;
                case "short":
                    buffer = BitConverter.GetBytes(Convert.ToInt16(value));
                    break;
                case "ushort":
                    buffer = BitConverter.GetBytes(Convert.ToUInt16(value));
                    break;
                case "float":
                    buffer = BitConverter.GetBytes(Convert.ToSingle(value));
                    break;
                case "double":
                    buffer = BitConverter.GetBytes(Convert.ToDouble(value));
                    break;
                case "char":
                    buffer = BitConverter.GetBytes(Convert.ToChar(value));
                    break;
                case "decimal":
                    int[] iBits = Decimal.GetBits(Convert.ToDecimal(value));
                    buffer = new byte[16];
                    for (int i = 0; i < 4; i++)
                    {
                        Array.Copy(BitConverter.GetBytes(iBits[i]), 0, buffer, i * 4, 4);
                    }
                    break;
                case "byte":
                    buffer = new byte[] { (Convert.ToByte(value)) };
                    break;
                case "datetime":
                    buffer = BitConverter.GetBytes(DateTime.Parse(value.ToString()).ToBinary());
                    break;
                case "guid":
                    buffer = ((Guid)(Convert.ChangeType(value, typeof(Guid)))).ToByteArray();
                    break;
                case "string":
                    buffer = System.Text.Encoding.UTF8.GetBytes(value.ToString());//System.Text.Encoding.GetEncoding("gb2312")
                    break;
                default:
                    throw new Exception("不能识别的数据类型，无法转换。请使用c#.net类型。");
                    break;
            }
            return buffer;
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            throw new NotSupportedException("流不支持写入操作");
        }
    }
}